package com.kevin.table;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.kevin.enums.BreakOp;
import com.kevin.exceptions.ExceptionFactory;
import com.kevin.utils.common.KnCommonUtils;

public class MDataTable {
	/**
	 * 动态存储数据
	 */
	private Object dynamicData;
	
	private String tableName;
	
	private String description;
	
	private MDataColumn columns;
	
	private Integer total;
	
	private String executorName;
	
	
	public MDataTable(){
		init("default", null);
	}
	
	public MDataTable(String tableName){
		init(tableName, null);
	}
	
	public MDataTable(String tableName,MDataColumn dcol){
		init(tableName, dcol);
	}
	
	/**
	 * 新建一行
	 * @param isAddToTable 将新建的行添加到当前表中
	 * @return
	 */
	public MDataRow createRow(Boolean isAddToTable){
		MDataRow mdr = new MDataRow(this);
		if(isAddToTable){
			rows.add(mdr,false);
		}
		return mdr;
	}
	
	public Map<String,Object> toMap(){
		Map<String,Object> tableMap = new HashMap<>();
		if(rows.size() == 0) return tableMap;
		ArrayList<Map<String,Object>> rowList = new ArrayList<>();
		tableMap.put("rows", rowList);
		for (MDataRow row : rows) {
			Map<String, Object> rowMap = new HashMap<>();			
			for (MDataCell cell : row) {
				Class<?> valueType = cell.getCellstruct().getValueType();
				if(KnCommonUtils.isNumber(valueType)){
					rowMap.put(cell.getColumnName(), cell.getValue());
				}else{
					rowMap.put(cell.getColumnName(), cell.getStringValue());
				}
				
			}
			if(rowMap.size() > 0){
				rowList.add(rowMap);
			}
		}	
		return tableMap;
		
	}
	
	private MDataRowCollection rows;

	/**
	 * 通过查询数据加载到相应的表中
	 * @param rs
	 * @return
	 * @throws SQLException 
	 */
	public void loadData(ResultSet rs){
		MDataRow mRecord = null;		
		try {
			while (rs.next()) {
				mRecord = createRow(true);
				for (int i = 0; i < columns.size(); i++) {
					Object value = null;		
					
					value = rs.getObject(mRecord.get(i).getColumnName());
					
					if(value == null){
						mRecord.get(i).setValue(StringUtils.EMPTY);
						mRecord.get(i).setState(0);
					}else if(value.toString().equals(StringUtils.EMPTY)){
						mRecord.get(i).setValue(StringUtils.EMPTY);
						mRecord.get(i).setState(1);
					}else{
						mRecord.get(i).setValue(value);
						mRecord.get(i).setState(2);
					}
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw ExceptionFactory.Exception("failed to load ResultSet value into MDataTable", e);
		}		
	}
	
	private void init(String tableName,MDataColumn dcol){
		rows = new MDataRowCollection(this);
		this.tableName = tableName;
		if(this.columns == null){
			columns = new MDataColumn(this);
			if(dcol != null){
				columns.addRange(dcol);
			}
		}
	}
	
	/**
	 * 加载行，包含相应的行结构（只有表为空架构时进行操作）
	 * @param row
	 */
	public void loadRow(MDataRow row) 
    {
        if (this.getColumns().size() == 0 && row != null && row.size() > 0)
        {
            this.setColumns(row.getColumns().clone());
            if (StringUtils.isNotEmpty(tableName) && tableName.startsWith("SysDefault"))
            {
            	tableName = row.getTableName();
            }
            //executorName = row.getExecutorName();
            //此行存在单元格
            if (!row.get(0).isEmpty())
            {
            	createRow(true).loadFrom(row);
                //_Rows.Add(row);
            }
        }
    }
	
	public void loadRowStruct(MDataRow row) {
        if (this.getColumns().size() == 0 && row != null && row.size() > 0)
        {
            this.setColumns(row.getColumns().clone());
            if (StringUtils.isNotEmpty(tableName) && tableName.startsWith("SysDefault"))
            {
            	tableName = row.getTableName();
            }
            //executorName = row.getExecutorName();
        }
	}
	
	public MDataRowCollection getRows() {
		return rows;
	}

	public void setRows(MDataRowCollection rows) {
		this.rows = rows;
	}

	public Object getDynamicData() {
		return dynamicData;
	}

	public void setDynamicData(Object dynamicData) {
		this.dynamicData = dynamicData;
	}

	public String getTableName() {
		return tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public MDataColumn getColumns() {
		return columns;
	}

	public void setColumns(MDataColumn columns) {
		this.columns = columns;
	}

	public String getExecutorName() {
		return executorName;
	}

	public void setExecutorName(String executorName) {
		this.executorName = executorName;
	}

	public Integer getTotal() {
		return total;
	}

	public void setTotal(Integer total) {
		this.total = total;
	}
	
    public <T> ArrayList<T> columnItems(Class<T> clazz,String columnName, BreakOp op, boolean isDistinct)
    {
        int index = -1;
        if (getColumns() != null)
        {
            index = getColumns().indexOf(columnName);
        }
        return columnItems(clazz,index, op, isDistinct);
    }
	
	public <T> ArrayList<T> columnItems(Class<T> clazz,int columnIndex, BreakOp op, boolean isDistinct){
		ArrayList<T> items = new ArrayList<T>();
        if (getColumns() != null && getRows() != null && getRows().size() > 0)
        {
            if (columnIndex > -1)
            {
                MDataCell cell;
                for (MDataRow row : getRows())
                {
                    cell = row.get(columnIndex);
                    switch (op)
                    {
                        case NULL:
                            if (cell.isNull())
                            {
                                continue;
                            }
                            break;
                        case EMPTY:
                            if (cell.getStringValue().equals(StringUtils.EMPTY))
                            {
                                continue;
                            }
                            break;
                        case NULLOREMPTY:
                            if (cell.isEmpty())
                            {
                                continue;
                            }
                            break;
                    }
                    T value = row.get(columnIndex, KnCommonUtils.getDefault(clazz),clazz);
                    if (!isDistinct || !items.contains(value))
                    {
                        items.add(value);
                    }
                }
            }
            else
            {
                //Error.Throw(string.Format("Table {0} can not find the column", TableName));
            }
        }
        return items;
    }
	
	public MDataTable getSchema(boolean clone){
        MDataTable newTable = new MDataTable(tableName);
        if (getColumns().size() > 0)
        {
            newTable.setColumns(clone ? getColumns().clone() : getColumns());
        }
        newTable.executorName = executorName;
        return newTable;
	}
	
	public MDataTable[] split(Object where){
		return MTableFilter.split(this, where);
	}
	
    public int getCount(Object where)
    {
        return MTableFilter.getCount(this, where);
    }
    
    public int getIndex(Object where)
    {
        return MTableFilter.getIndex(this, where);
    }
    
    public MDataRowCollection findAll(Object where)
    {
        return MTableFilter.findAll(this, where);
    }
    
    public MDataRow findRow(Object where)
    {
        return MTableFilter.findRow(this, where);
    }
    
    public MDataTable Select(Object where)
    {
        return select(0, 0, where);
    }
    
    public MDataTable Select(int topN, Object where)
    {
        return select(1, topN, where);
    }
    
    public MDataTable select(int pageIndex, int pageSize, Object where, Object... selectColumns)
    {
        return MTableFilter.select(this, pageIndex, pageSize, where, selectColumns);
    }
    
    public <T> List<T> getColumnItems(String columnName,Class<T> clazz)
    {
        return getColumnItems(columnName, BreakOp.NONE, false,clazz);
    }
    
    public <T> List<T> getColumnItems(String columnName, BreakOp op,Class<T> clazz)
    {
        return getColumnItems(columnName, op, false,clazz);
    }
    
    public <T> List<T> getColumnItems(String columnName, BreakOp op, boolean isDistinct,Class<T> clazz)
    {
        int index = -1;
        if (getColumns() != null)
        {
            index = getColumns().indexOf(columnName);
        }
        return getColumnItems(index, op, isDistinct,clazz);
    }
    
    public <T> List<T> getColumnItems(int columnIndex,Class<T> clazz)
    {
        return getColumnItems(columnIndex, BreakOp.NONE,clazz);
    }
    
    public <T> List<T> getColumnItems(int columnIndex, BreakOp op,Class<T> clazz)
    {
        return getColumnItems(columnIndex, op, false,clazz);
    }
    
    public <T> List<T> getColumnItems(int columnIndex, BreakOp op, boolean isDistinct,Class<T> clazz)
    {
        List<T> items = new ArrayList<>();
        if (getColumns() != null && getRows() != null && getRows().size() > 0)
        {
            if (columnIndex > -1)
            {
                MDataCell cell;
                for (MDataRow row : getRows())
                {
                    cell = row.get(columnIndex);
                    switch (op)
                    {
                        case NULL:
                            if (cell.isNull())
                            {
                                continue;
                            }
                            break;
                        case EMPTY:
                            if (cell.getStringValue().equals(StringUtils.EMPTY))
                            {
                                continue;
                            }
                            break;
                        case NULLOREMPTY:
                            if (cell.isEmpty())
                            {
                                continue;
                            }
                            break;
                    }
                    T value = row.get(columnIndex, clazz);
                    if (!isDistinct || !items.contains(value))
                    {
                        items.add(value);
                    }
                }
            }
            else
            {
                //Error.Throw(string.Format("Table {0} can not find the column", TableName));
            }
        }
        return items;
    }
}
